JS - web components

Revision:


Content

some web component examples HTML template - shadow DOM - custom elements - some applications


some web component examples

top

first example

example: header component
code:
                    <header-component></header-component>
                    <script>
                        const headerTemplate = document.createElement('template');
                            headerTemplate.innerHTML = `
                                <style>
                                    .header{text-align: center;}
                                    h3{color: blue; font-size: 1.5vw;}
                                </style>
                                <div>
                                    <div class="header">
                                        <h3> Header - my initial reflections with respect to web components </h3>
                                    </div>
                                </div>`
                        class Header extends HTMLElement {
                            constructor() {
                                super();
                            }
                            connectedCallback(){
                                const shadowRoot = this.attachShadow({ mode: 'open' });
                                shadowRoot.appendChild(headerTemplate.content);
                            }
                        }
                        customElements.define('header-component', Header);
                    </script>
                

second example

example: extend HTML element - color
code:
                    <my-component></my-component>
                    <script>
                        class MyComponent extends HTMLElement {
                            constructor() {
                                super()
                                this.attachShadow({mode: 'open'}).innerHTML = `
                                    <style>
                                        span {color: darkblue;}
                                    </style>
                                    <span>The color of this sentence should be darkblue</span>
                                    `
                            }
                        }
                        customElements.define('my-component', MyComponent)
                    </script>
                

third example

example: extend HTML element - background


code:
                    <div>
                        <first-component></first-component>
                        <second-component></second-component><br><br>
                    </div>
                    <script>
                        class FirstComponent extends HTMLElement {
                            constructor() {
                                super()
                                this.attachShadow({ mode: 'open' }).innerHTML = `
                                    <style>
                                        :host{--background: lightgreen;}
                                        span{background: var(--background);}
                                    </style>
                                    <span>Hi, there. This is the first component!</span><br><br>
                                `
                            }
                        }
                        class SecondComponent extends HTMLElement {
                            constructor() {
                                super()
                                this.attachShadow({ mode: 'open' }).innerHTML = `
                                    <style>
                                        :host{--background: lightblue;}
                                        span{background: var(--background);}
                                    </style>
                                    <span>Hello, this is the second component!</span>
                                    `
                            }
                        }
                        customElements.define('first-component', FirstComponent)
                        customElements.define('second-component', SecondComponent)
                    </script>
                

fourth example

example: extend HTML element - font


code:
                    <div>
                        <first-component-a></first-component-a><br><br>
                        <second-component-a></second-component-a>
                    </div>
                    <script>
                        class FirstComponentA extends HTMLElement {
                            constructor() {
                            super()
                            this.attachShadow({ mode: 'open' }).innerHTML = `
                                    <style>
                                    :host{--background: lightgreen;}
                                    span{background: var(--background);}
                                    </style>
                                    <span>Hello, this is the "FIRST" component!</span>
                                `
                            }
                        }
                        class SecondComponentA extends HTMLElement {
                            constructor() {
                            super()
                            this.attachShadow({ mode: 'open' }).innerHTML = `
                                    <style>
                                    :host{--background: lightblue;}
                                    span{background: var(--background);}
                                    </style>
                                    <span>Hello, this is the "SECOND" component!</span>
                                `
                            }
                        }
                        customElements.define('first-component-a', FirstComponentA)
                        customElements.define('second-component-a', SecondComponentA)
                    </script>
                

fifth example

example: attach shadow
Default:

Dark:

Light:

code:
                    <div>
                        <div>Default:
                            <custom-component></custom-component>
                        </div><br>
                        <div>Dark:
                            <custom-component class="dark"></custom-component>    
                        </div><br>
                        <div>Light:
                            <custom-component class="light"></custom-component>
                        </div><br>
                    </div>
                    <script>
                        class CustomComponent extends HTMLElement {
                            constructor() {
                                super()
                                this.attachShadow({ mode: 'open' }).innerHTML = `
                                    <style>
                                        :host, :host(.light) {background: white; color: black;}
                                        :host(.dark) {background: black; color: white;}
                                        @media (prefers-color-scheme: dark) {
                                        :host {background: black; color: white;}
                                        }
                                    </style>
                                    <span>Hello world!</span>
                                    `
                            }
                        }
            
                        customElements.define('custom-component', CustomComponent)
                    </script>
                

sixth example

example: change font


code:
                    <div>
                        <label-uppercase value="Welcome to Web Components"></label-uppercase><br><br>
                    </div>
                    <script>
                        class UpperCaseLabel extends HTMLElement {
                            get value() {
                                return this.getAttribute("value");
                            }
                    
                            set value(newValue) {
                                this.setAttribute("value", newValue);
                            }
                    
                            connectedCallback() {
                            let stringContent = (this.value && null !== this.value) ? this.value : "";
                            this.innerHTML = `<label>${stringContent.toUpperCase()}</label>`;
                        }
                        }
                    
                        customElements.define("label-uppercase", UpperCaseLabel);
                    </script>
                


HTML template - shadow DOM - custom elements - some applications

top
example: choose your language
code:
            <div>
                <template id="my-drop-down">
                    <style>
                        .menu-wrap{width: 20.8334vw; display: block; background-color: transparent;   font-family: 'ExtraLight'; user-select: none; 
                        margin: 20px 40px;}
                        .menu-label{font-size: 1vw; color: rgba(227, 141, 39, .8);padding: 1% 0% 2.5% 7%;
                        }
                        .menu-head{border: 1px solid #e38d27;}
                        .menu-head, .menu-body {background-color: rgba(0, 0, 0, .6);}
                        .menu-head, ::slotted(.menu-option) {min-height: 2.2vw;}
                        .current-choice{color: #fff; height: 2.2vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; 
                        padding: .7vw .1vw .1vw 1.7vw;}
                        .current-choice, ::slotted(.menu-option){text-transform: capitalize; font-size: 1.2vw;}
                        .menu-body{max-height: 13vw; overflow-y: scroll; overflow-x: hidden;}
                        ::slotted(.menu-option) {color: rgba(255, 255, 255, .3); position: relative; padding-left: 1.7vw; display: flex; 
                        align-items: center; transition: padding .5s linear, background-color .25s linear, color .25s linear;}
                        ::slotted(.menu-option::after){content: ''; width: 100%; height: 1px;background-color: rgba(255, 255, 255, .15); 
                        position: absolute; bottom: 0; left: 0;          }
                        ::slotted(.menu-option:hover){background-color: #e38d27; color: #fff;padding-left: 12%;}
                        .menu-body::-webkit-scrollbar {width: 2.292vw;}
                        .menu-body::-webkit-scrollbar-thumb {background-color: #e38d27; border: .78125vw solid rgba(0, 0, 0, 0); 
                        background-clip: padding-box;}
                        .menu-body::-webkit-scrollbar-track {background-color: #111; border: .78125vw solid black;}
                    </style>
                    <div id="my-menu" class="menu-wrap">
                        <div class="menu-label">Choose your language</div>
                        <div class="menu-head"><div class="current-choice">English</div></div>
                        <div id="menu-body" class="menu-body">
                        <slot></slot>
                        </div>
                    </div>
                </template>
                <drop-down>
                    <div class="menu-option">English</div>
                    <div class="menu-option">Deutsch</div>
                    <div class="menu-option">Espanol</div>
                    <div class="menu-option">Magyar</div>
                    <div class="menu-option">Dansk</div>
                    <div class="menu-option">Euskara</div>
                    <div class="menu-option">Hrvatski</div>
                    <div class="menu-option">Italiano</div>
                </drop-down>
                <drop-down>
                    <div class="menu-option">English</div>
                    <div class="menu-option">Deutsch</div>
                </drop-down>
                <drop-down>
                    <div class="menu-option">English</div>
                    <div class="menu-option">Deutsch</div>
                    <div class="menu-option">Espanol</div>
                    <div class="menu-option">Magyar</div>
                    <div class="menu-option">Dansk</div>
                    <div class="menu-option">Euskara</div>
                    <div class="menu-option">Hrvatski</div>
                    <div class="menu-option">Italiano</div>
                    <div class="menu-option">English</div>
                    <div class="menu-option">Deutsch</div>
                    <div class="menu-option">Espanol</div>
                    <div class="menu-option">Magyar</div>
                    <div class="menu-option">Dansk</div>
                    <div class="menu-option">Euskara</div>
                    <div class="menu-option">Hrvatski</div>
                    <div class="menu-option">Italiano</div>
                    <div class="menu-option">English</div>
                    <div class="menu-option">Deutsch</div>
                </drop-down>
                </div>    
            <script>
                class DropDown extends HTMLElement {
                    constructor() {
                    super();
                    }
        
                connectedCallback() {
                    // init the component
                    let shadowDOM = this.attachShadow({ mode: "open" });
                    let template = document.getElementById("my-drop-down");
                    let templateHtml = template.content.cloneNode(true);
                    shadowDOM.appendChild(templateHtml);
        
                    // define the menu, menu body and hide it
                    let menu = shadowDOM.getElementById("my-menu");
                    let menuHead = menu.children[1];
                    let menuBody = menu.children[2];
                    menuBody.style.display = "none";
        
                    // toggle the menu body
                    function toggleMenu() {
                    menuHead.addEventListener("click", function() {
                        if (menuBody.style.display === "none") {
                        menuBody.style.display = "block";
                        } else {
                        menuBody.style.display = "none";
                        }
                    });
        
                    menuBody.addEventListener("click", function(ev) {
                        if (ev.target !== ev.currentTarget) {
                        menuHead.children[0].textContent = ev.target.textContent;
                        }
        
                        menuBody.style.display = "none";
                    });
                    }
                    // init toggle listeners
                    toggleMenu();
                }
                }
        
                // init the element
                customElements.define("drop-down", DropDown);
                </script>
            

example: counter
code:
            <my-counter></my-counter>
            <script>
                class MyCounter extends HTMLElement {
                constructor() {
                    super();
                    this.count = 0;
        
                    const style = `
                    *{font-size: 200%;}
                    span{width: 4rem; display: inline-block; text-align: center;}
                    button{width: 64px; height: 64px; border: none; border-radius: 10px;   background-color: seagreen; color: white;}
                    `;
        
                    const html = `
                    <button id="dec">-</button>
                    <span>${this.count}</span>
                    <button id="inc">+</button>
                    `;
        
                    this.attachShadow({ mode: 'open' });
                    this.shadowRoot.innerHTML = `
                    <style>
                    ${style}
                    </style>
                    ${html}
                    `;
        
                    this.buttonInc = this.shadowRoot.getElementById('inc');
                    this.buttonDec = this.shadowRoot.getElementById('dec');
                    this.spanValue = this.shadowRoot.querySelector('span');
        
                    this.inc = this.inc.bind(this);
                    this.dec = this.dec.bind(this);
                    }
        
                    inc() {
                        this.count++;
                        this.update();
                    }
        
                    dec() {
                        this.count--;
                        this.update();
                    }
        
                    update() {
                        this.spanValue.innerText = this.count;
                    }
        
                    connectedCallback() {
                        this.buttonInc.addEventListener('click', this.inc);
                        this.buttonDec.addEventListener('click', this.dec);
                    }
        
                    disconnectedCallback() {
                        this.buttonInc.removeEventListener('click', this.inc);
                        this.buttonDec.removeEventListener('click', this.dec);
                    }
                }
        
                customElements.define('my-counter', MyCounter);
        
            </script>
            </pre>
        

example: timer
Lap 1 time

Lonely, unstyled paragraph.

code:
            <div>
            <template id="cool-timer">
                <style>
                    p.timer-display { display: block; padding: 2w;  border-radius: 0.5vw; font-size: 3vw; border: 1px solid #212121; 
                    color: #212121; background: #fff; }
                    p {background: #eb6; color: #212121; padding: 0.5vw; }
                </style>
                <p class="timer-display"><span id="timer">0</span> seconds</p>
                <p>
                    <!-- A custom description that can be overridden in markup -->
                    <slot name="timer-description">A cool timer worth the attention!</slot>
                </p>
            </template>
            <!-- Actual, rendered instance of the cool timer -->
            <cool-timer><span slot="timer-description">Lap 1 time</span></cool-timer>
            <p>Lonely, unstyled paragraph.</p>
        </div>
        <script>
                class CoolTimer extends HTMLElement {
                    constructor(){
                        super();
                        const template = document.getElementById("cool-timer");
                        const templateContent = template.content;
                        const shadowRoot = this.attachShadow({ mode: "open" }).appendChild( templateContent.cloneNode(true));
                    }
                    // Called when the element is first connected to the DOM
                    connectedCallback() {
                        const timerDisplay = this.shadowRoot.getElementById("timer");
                        let elapsedSeconds = 0;
                        // Every second, increment elapsed seconds and update timer display
                        this.timer = setInterval(() => {
                        elapsedSeconds++;
                        timerDisplay.innerHTML = elapsedSeconds;
                        }, 1000);
                    }
                    // Called when custom element is removed
                    disconnectedCallback() {
                        if (this.timer) {
                        clearInterval(this.timer);
                        this.timer = null;
                        }
                    }
                }
                customElements.define("cool-timer", CoolTimer);
            </script>